#include "include/Session.h"
#include "include/Configuration.h"
#include "include/Singleton.h"

Logic::Logic(boost::asio::io_service &io_service)
	: _game_client(io_service), p_client(NULL)
{
}

Logic::~Logic()
{
}

int Logic::Init()
{
	server_key = ServerKey();
	session_key = SessionKey();

	if(Singleton<Configuration>::instance().server_info_map.find(server_key) ==
			Singleton<Configuration>::instance().server_info_map.end())
	{
		cout << "Can not find game server by server_key: " << server_key << endl;
		return 1;
	}

	Configuration::GameServerInfo *p_server_info = Singleton<Configuration>::instance().server_info_map[server_key];
	_game_client.Init(p_server_info->ip, p_server_info->port);

	// debug
	cout << "init done" << endl;
	// debug end

	return 0;
}

int Logic::ServerKey()
{
	return (int)((_package_head.server_type << 16) | _package_head.server);
}

int Logic::ServerKey(int server_type, int server_id)
{
	return (int)((((unsigned char)server_type) << 16) | ((unsigned short)server_id));
}

unsigned int Logic::SessionKey()
{
	return _package_head.player_id;
}

int Logic::GetPackageNum(char *buf, int len)
{
	_package_head_list.clear();

	struct Common::PackageHead *p_head = PackageUtil::GetPackageHead(buf);
	_package_head_list.push_back((char *)p_head);

	while(1 == p_head->multi_data)
	{
		p_head = PackageUtil::GetNextPackageHead(p_head);

		if((char *)p_head - buf > len)
		{
			break;
		}

		_package_head_list.push_back((char *)p_head);
	}

	return _package_head_list.size();
}

enum LogicResult Logic::ProcessDownStreamPackage(int index, char *&p_data, int &len)
{
	if((unsigned int)index >= _package_head_list.size())
	{
		// debug
		std::cout << "error 1" << std::endl;
		// debug end
		return LogicError;
	}

	if(ParseHead(_package_head_list[index]))
	{
		// debug
		std::cout << "error 2" << std::endl;
		// debug end
		return LogicError;
	}

	drop_info_len = 0;
	p_data = _package_head_list[index];
	len = PackageUtil::GetPackageLen(p_data);

	switch((enum Common::DataType)_package_head.append_data)
	{
		case Common::NormalData:
			// debug
			std::cout << "right data" << std::endl;
			// debug end
			return LogicNormalData;

		case Common::BroadcastData:
		{
			return LogicBroadcastData;
		}
			break;

		case Common::MulticastData:
		{
			struct Common::MulticastHead *p_multicast_head = PackageUtil::GetMulticastHead(p_data);

			// set multicast information
			multicast_player_num = p_multicast_head->player_num;
			p_multicast_player_id = (unsigned int *)((char *)p_multicast_head + sizeof(struct Common::MulticastHead));
			drop_info_len = sizeof(struct Common::MulticastHead) + multicast_player_num * sizeof(unsigned int);
			PackageUtil::GetPackageHead(p_data)->length -= drop_info_len;

			return LogicMulticastData;
		}
			break;

		default:
			break;
	}
	// debug
	std::cout << "process down data error 3" << std::endl;
	// debug end

	return LogicError;
}

enum LogicResult Logic::ProcessUpStreamData(char *buf, int len)
{
	if(len <= sizeof(struct Common::PackageHead))
	{
		// debug
		std::cout << "error 1" << std::endl;
		// debug end
		return LogicError;
	}

	if(ParseHead(buf))
	{
		// debug
		std::cout << "ParseHead Error" << std::endl;
		// debug end
		return LogicError;
	}

	switch((enum Common::ServerType)_package_head.server_type)
	{
		case Common::GameServerType:
			p_client = &_game_client;

			if(_game_client.is_connect)
			{
				return LogicNeedWrite;
			}
			else
			{
				// debug
				cout << "need connect" << endl;
				// debug end
				if(Init())
				{
					break;
				}

				return LogicNeedConnect;
			}

		default:
			break;
	}
	// debug
	std::cout << "error 3" << std::endl;
	// debug end

	return LogicError;
}

int Logic::ParseHead(char * buf)
{
	struct Common::PackageHead *p_head = PackageUtil::GetPackageHead(buf);

	_package_head.version = p_head->version;
	_package_head.protocol = p_head->protocol;
	_package_head.player_id = p_head->player_id;
	_package_head.server_type = p_head->server_type;
	_package_head.server= p_head->server;
	_package_head.append_data = p_head->append_data;

	// debug
	cout << "version: " << (int)_package_head.version << endl;
	cout << "protocol: " << (int)_package_head.protocol << endl;
	cout << "player_id: " << (int)_package_head.player_id << endl;
	cout << "server_type: " << (int)_package_head.server_type << endl;
	cout << "server: " << (int)_package_head.server << endl;
	cout << "append_data: " << (int)_package_head.append_data << endl;
	// debug end


	if(_package_head.protocol != Singleton<Configuration>::instance().protocol)
	{
		// debug
		std::cout << "protocol error: " << _package_head.protocol << std::endl;
		// debug end
		return 1;
	}
	if(_package_head.version != Singleton<Configuration>::instance().version)
	{
		// debug
		std::cout << "version error: " << _package_head.version << std::endl;
		// debug end
		return 1;
	}
	if(0 == _package_head.player_id && Common::MulticastData != _package_head.append_data &&
		Common::BroadcastData != _package_head.append_data)
	{
		// debug
		std::cout << "player_id error: " << _package_head.player_id << std::endl;
		std::cout << "append_data: " << _package_head.append_data << endl;
		// debug end
		return 1;
	}

	return 0;
}
